﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Collections;
using System.Threading;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System.Windows.Forms;

namespace ChatTool
{
    /// <summary>
    /// 组播网络管理
    /// </summary>
    public class NetManager
    {
        private IPAddress broderCastIp = IPAddress.Parse("224.100.0.2");//组播地址
        private IPAddress broderCastGroupIp = IPAddress.Parse("224.100.0.3");//群组消息组播地址
        private int sendPort = 56299;//组播时本机要接收组播信息的监听端口 同时也是本机要发布组播信息要到的远程端口
        private int sendGroupPort = 56300;//群组消息组播端口

        public delegate void UserInfoReceivedDelegate(User user);
        public event UserInfoReceivedDelegate UserInfoReceived;
        public delegate void GroupInfoReceivedDelegate(Group group);
        public event GroupInfoReceivedDelegate GroupInfoReceived;
        public delegate void GroupMsgReceivedDelegate(Object obj);
        public event GroupMsgReceivedDelegate GroupMsgReceived;


        public static int listenerPort = 3523;//本端监听的端口
        private MyServer myServer;//tcp监听服务端
        /// <summary>
        /// 随机数产生对象
        /// </summary>
        public static Random random = new Random();

        private FormManager formManager;
        public NetManager(FormManager formManager)
        {
            this.formManager = formManager;

        }
        public NetManager() { }
        /// <summary>
        /// 开启网络的组播方式监听，接收网络上的用户组播消息
        /// </summary>
        public void StartListenerThread()
        {
            Thread receiveThread = new Thread(ResolveUser);
            receiveThread.IsBackground = true;
            receiveThread.Start();

            //开启 TCP监听
            NetManager.listenerPort = NetManager.GetAvailablePort();
            this.formManager.UserOwn.ListenerPort = NetManager.listenerPort;
            this.formManager.UserOwn.Ip = NetManager.GetHostIP().ToString();
            myServer = new MyServer(listenerPort, this.formManager);
            myServer.StartListen();
        }
        //监听方法体
        private void ResolveUser()
        {
            //定义UdpClient对象
            UdpClient udpClient = null;
            try
            {
                //初始化UdpClient对象
                udpClient = new UdpClient(sendPort);
                udpClient.JoinMulticastGroup(broderCastIp);
                udpClient.Ttl = 200;
                IPEndPoint remoteIPEndPoint = new IPEndPoint(IPAddress.Any, 0);
                while (true)
                {
                    try
                    {
                        byte[] bs = udpClient.Receive(ref remoteIPEndPoint);
                        Object obj = FileOperate.Deserialize(bs);
                        if (obj is User)
                        {
                            if (UserInfoReceived != null)
                                UserInfoReceived(obj as User);//触发事件
                        }
                        else if (obj is Group)
                        {
                            if (GroupInfoReceived != null)
                                GroupInfoReceived(obj as Group);
                        }
                        
                    }
                    catch (Exception)
                    {
                        continue;
                    }
                }
            }
            catch (Exception e)
            {
                MessageBox.Show("接收组播消息异常：" + e.Message);
            }
            finally
            {
               // udpClient.Close();
            }
        }
        /// <summary>
        /// 开启群组消息监听
        /// </summary>
        public void StartListenGroupMsg()
        {
            Thread receiveThread = new Thread(ResolveGroupMsg);
            receiveThread.IsBackground = true;
            receiveThread.Start();
        }
        
        private void ResolveGroupMsg()
        {
            UdpClient udpClient = null;
            try
            {
                udpClient = new UdpClient(sendGroupPort);
                udpClient.JoinMulticastGroup(broderCastGroupIp);
                udpClient.Ttl = 200;
                IPEndPoint remoteIPEndPoint = new IPEndPoint(IPAddress.Any, 0);
                SortedList<byte, byte[]> msgList = new SortedList<byte, byte[]>();
                int totalLength = 0;
                for (int i = 0; i < time; i++)
                {
                    byte bs = Convert.ToByte(i);
                    numByteList.Add(bs);
                }
                bool isBegin = true;
                string lockIp = "";
                while (true)//这里最好设置一个条件变量 来控制循环的结束
                {
                    try
                    {
                        byte[] bs = udpClient.Receive(ref remoteIPEndPoint);
                        byte key = bs[0];
                        if (key == Byte.MaxValue)
                        {
                            Byte[] bss = new Byte[bs.Length - 1];
                            Array.Copy(bs, 1, bss, 0, bss.Length);
                            try
                            {
                                Object obj = FileOperate.Deserialize(bss);
                                if (GroupMsgReceived != null)
                                    GroupMsgReceived(obj);
                            }
                            catch (Exception)
                            { }
                            continue;
                        }
                        
                        if (key == numByteList[0] && (lockIp == "" || lockIp == remoteIPEndPoint.Address.ToString()))
                        {
                            lockIp = remoteIPEndPoint.Address.ToString();
                            isBegin = true;
                            msgList.Clear();
                            totalLength = 0;
                        }
                        if (isBegin == true && lockIp == remoteIPEndPoint.Address.ToString())
                        {
                            if (msgList.ContainsKey(key) == false)
                            {
                                totalLength += (bs.Length - 1);//累加十次的接收字节总长度 除去标记一个字节
                                msgList.Add(key, bs);
                                if (msgList.Count == time)
                                {
                                    byte[] imageBs = new byte[totalLength];
                                    int startPos = 0;//重组字节时每次的起始位置
                                    for (int i = 0; i < msgList.Count; i++)
                                    {
                                        for (int j = 1; j < msgList.Values[i].Length; j++)
                                        {
                                            imageBs[startPos + j - 1] = msgList.Values[i][j];
                                        }
                                        startPos += (msgList.Values[i].Length - 1);
                                    }
                                    try
                                    {
                                        Object obj = FileOperate.Deserialize(imageBs);
                                        if (GroupMsgReceived != null)
                                            GroupMsgReceived(obj);
                                    }
                                    catch (Exception)
                                    { }
                                    isBegin = false;
                                    lockIp = "";
                                }
                            }
                        }
                    }
                    catch (Exception)
                    {
                        continue;
                    }
                }
            
            }
            catch (Exception e)
            {
                MessageBox.Show("接收组播消息异常：" + e.Message);
            }
            finally
            {
                // udpClient.Close();
            }
        }
        private List<byte> numByteList = new List<byte>();//图片分割的序号Key值
        private int time = 20;
        /// <summary>
        /// 将群组消息发送出去
        /// </summary>
        /// <param name="obj"></param>
        public bool SendGroupMsg(Object obj)
        {
            UdpClient sendClient = new UdpClient(AddressFamily.InterNetwork);
            sendClient.Ttl = 200;
            IPEndPoint iep = new IPEndPoint(broderCastGroupIp, sendGroupPort);
            Byte[] bs = FileOperate.Serialize(obj);
            if (bs.Length < 63 * 1024)
            {
                //MessageBox.Show(bs.Length / 1024 + "vvvv");
                Byte[] bss = new Byte[bs.Length+1];
                bss[0] = Byte.MaxValue;
                Array.Copy(bs, 0, bss, 1, bs.Length);
                if (SendByteInfo(bss) == false)
                    return false;
                return true;
            }
            int everyLength = bs.Length / time;
            //MessageBox.Show(bs.Length / 1024 + "");
            
            for (int i = 0; i < time; i++)
            {
                if (i == 1)
                    Thread.Sleep(50);
                if (i < time - 1)
                {
                    byte[] sendBS = new byte[everyLength + 1];
                    sendBS[0] = numByteList[i];
                    for (int j = i * everyLength; j < (i + 1) * everyLength; j++)
                    {
                        sendBS[j - i * everyLength + 1] = bs[j];
                    }
                    if (SendByteInfo(sendBS) == false)
                        return false;
                }
                else
                {
                    byte[] sendBS = new byte[bs.Length - everyLength * i + 1];
                    sendBS[0] = numByteList[i];
                    for (int j = i * everyLength; j < bs.Length; j++)
                    {
                        sendBS[j - i * everyLength + 1] = bs[j];
                    }
                    if (SendByteInfo(sendBS) == false)
                        return false;
                }
            }
            return true;
        }
        /// <summary>
        /// 将字节信息通过组播发送出去
        /// </summary>
        private bool SendByteInfo(byte[] bs)
        {
            UdpClient sendClient = new UdpClient(AddressFamily.InterNetwork);
            sendClient.Ttl = 200;
            IPEndPoint iep = new IPEndPoint(broderCastGroupIp, sendGroupPort);
            try
            {
                sendClient.Send(bs, bs.Length, iep);
                return true;
            }
            catch (Exception) 
            { 
                //MessageBox.Show(ee.Message); 
                return false;
            }
            finally
            {
                sendClient.Close();
            }
        }
        /// <summary>
        /// 将自己的登陆信息组播出去
        /// </summary>
        public void StartBroadcastThread(Object user)
        {
            Thread receiveThread = new Thread(BroadcastOwn);
            receiveThread.IsBackground = true;
            receiveThread.Start(user);
        }
        //组播信息方法体
        private void BroadcastOwn(Object obj)
        {
            UdpClient sendClient = new UdpClient(AddressFamily.InterNetwork);
            sendClient.Ttl = 200;
            IPEndPoint iep = new IPEndPoint(broderCastIp, sendPort);
            Byte[] bs = FileOperate.Serialize(obj);
            try
            {
                sendClient.Send(bs, bs.Length, iep);
            }
            catch 
            {
                MessageBox.Show("组播自己的信息失败!");
            }
            finally
            {
                sendClient.Close();
            }
        }
      
        /// <summary>
        /// 获取本机的IPV4地址
        /// </summary>
        public static IPAddress GetHostIP()
        {
            IPAddress[] ips = Dns.GetHostAddresses(Dns.GetHostName());
            foreach (IPAddress ip in ips)
            {
                if (ip.AddressFamily == AddressFamily.InterNetwork)
                    return ip;
            }
            return ips[0];
        }
        /// <summary>
        /// 获取一个本机可用的端口号
        /// </summary>
        public static int GetAvailablePort()
        {
            int port;
            TcpListener testListener; 
            while (true)
            {
                port = NetManager.random.Next(1024, 5000);
                try
                {
                    testListener = new TcpListener(NetManager.GetHostIP(), port);
                    testListener.Start();
                }
                catch
                {
                    continue;
                }
                testListener.Stop();
                return port;
            }
        }
        /// <summary>
        /// 与远程服务器建立TCP连接 成功返回建立的UserClient对象 失败 返回null
        /// </summary>
        public UserClient ConnectToServer(User remoteUser)
        {
            TcpClient client = new TcpClient(AddressFamily.InterNetwork);
            try
            {
                IPEndPoint ipe = new IPEndPoint(IPAddress.Parse(remoteUser.Ip), remoteUser.ListenerPort);
                client.Connect(ipe);//连接服务器
                return new UserClient(client);
            }
            catch
            {
                client.Close();
                return null;
            }
        }
        /// <summary>
        /// 向服务器发送字符串命令或信息
        /// </summary>
        public static bool SendStringMsgToServer(UserClient userClient, string msg)
        {
            try
            {
                userClient.Bw.Write(msg);
                userClient.Bw.Flush();
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }
        /// <summary>
        /// 向服务器发送字节信息
        /// </summary>
        public static bool SendBytesMsgToServer(UserClient userClient, byte[] bs)
        {
            try
            {
                userClient.Bw.Write(bs.Length);
                userClient.Bw.Write(bs);
                userClient.Bw.Flush();
                return true;
            }
            catch (Exception)
            {
                return false;
            }
           
        }
    }
}
